﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "CmdEditRoofProfile.h"
#include "GmUiStructureCommandRegister.h"
#include "StructureCmdIds.h"

#include "IInstance.h"
#include "ElementId.h"
#include "IFamily.h"
#include "UserTransactionGroupUtils.h"
#include "IUserTransaction.h"
#include "IEditMode.h"
#include "StructureEditModeTypes.h"
#include "IStructureRoofEditModeBehavior.h"
#include "IStructureFloorEditModeBehavior.h"
#include "IElementBasicInformation.h"
#include "IElementPosition.h"
#include "Matrix4d.h"
#include "IElementTransformationComponent.h"
#include "ISelection.h"
#include "ICommandManager.h"
#include "UniIdentity.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "IDocument.h"
#include "IUiDocument.h"
#include "IStructureRoof.h"
#include "IElementStatus.h"
#include "IType.h"
#include "StructureRoofProfileUsedModelLineUtils.h"
#include "IHighlights.h"
#include "UiDocumentViewUtils.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

REGISTER_GM_COMMAND(CmdEditRoofProfile)

CmdEditRoofProfile::CmdEditRoofProfile(const std::wstring& cmdId)
    : CmdEditDrawProfileBase(cmdId)
{
}

CmdEditRoofProfile::~CmdEditRoofProfile()
{
}

OwnerPtr<IAction> CmdEditRoofProfile::ExecuteCommand(const CommandParameters& cmdParams)
{
    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IInstance* pEditingInstance = GetSelectedInstance();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pEditingInstance, L"未能成功获取选中Instance",L"GDMPLab",L"2024-03-30");

    ElementId editingInstanceId = pEditingInstance->GetElementId();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(editingInstanceId.IsValid(), L"editingInstanceId无效",L"GDMPLab",L"2024-03-30");

    const IFamily * pFamily = pEditingInstance->GetFamily();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pFamily, L"未能成功获取族类型",L"GDMPLab",L"2024-03-30");

    int groupId;
    UserTransactionGroupUtils::Start(pDoc, GBMP_TR(L"编辑屋顶轮廓"), groupId);
    OwnerPtr<IUserTransaction> opTransaction = IUserTransaction::Create(pDoc, GBMP_TR(L"开始编辑屋顶"));

    IEditMode* pProfileEditMode = IEditMode::Get(pDoc, StructureEditModeTypes::StructureRoofProfileModeType);
    if (!pProfileEditMode)
    {
        pProfileEditMode = IEditMode::Create(pDoc, IStructureRoofEditModeBehavior::Create());
    }
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pProfileEditMode, L"pProfileEditMode为空",L"GDMPLab",L"2024-03-30");

    IStructureRoofEditModeBehavior* pProfileBehavior = quick_cast<IStructureRoofEditModeBehavior>(pProfileEditMode->GetEditModeBehavior());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pProfileBehavior, L"pProfileBehavior为空",L"GDMPLab",L"2024-03-30");
    
    pProfileBehavior->SetEditingFamilyId(pFamily->GetElementId());
    pProfileBehavior->SetEditingInstanceTypeId(pEditingInstance->GetBasicInformation()->GetType()->GetElementId());

    // 进入编辑过程
    pProfileEditMode->StartEditing(pDoc, editingInstanceId, false, false);

    // 设置轮廓线的可见性
    std::vector<IElement*> profileCurveElements;
    std::vector<IElement*> slopeLineElements;
    this->GetProfileCurvesAndSlopeLines(editingInstanceId, profileCurveElements, slopeLineElements);

    const IElementPosition* posBehavior = pEditingInstance->GetElementPosition();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posBehavior, L"posBehavior为空",L"GDMPLab",L"2024-03-30");

    // 将轮廓线和坡度线从局部坐标系变回世界坐标系,并且设置可见性
    Matrix4d mat = posBehavior->ComputeLocalToWorldCoordinateSystemTransformMatrix();
    FOR_EACH(pProfileCurveElement, profileCurveElements)
    {
        IElementTransformationComponent* pTransformBehavior = pProfileCurveElement->GetElementTransformationComponent();
        DBG_WARN_AND_CONTINUE_UNLESS(pTransformBehavior, L"pTransformBehavior为空",L"GDMPLab",L"2024-03-30");
        pTransformBehavior->Transform(mat);
        IElementStatus* pStatus = pProfileCurveElement->GetStatus();
        DBG_WARN_AND_CONTINUE_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
        pStatus->SetIsVisible(true);
    }
    FOR_EACH(pSlopeLineElement, slopeLineElements)
    {
        IElementTransformationComponent* pTransformBehavior = pSlopeLineElement->GetElementTransformationComponent();
        DBG_WARN_AND_CONTINUE_UNLESS(pTransformBehavior, L"pTransformBehavior为空",L"GDMPLab",L"2024-03-30");
        pTransformBehavior->Transform(mat);
        IElementStatus* pStatus = pSlopeLineElement->GetStatus();
        DBG_WARN_AND_CONTINUE_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
        pStatus->SetIsVisible(true);
    } 

    // 设置屋顶实例的可见性
    IElementStatus* pStatus = pEditingInstance->GetStatus();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
    pStatus->SetIsVisible(false);

    opTransaction->Commit();

    // 清空选择集
    ISelection::Get()->Clear(pDoc);
    IHighlights::Get()->Clear();
    // 更新文档
    IUiDocument* pUiDoc = UiDocumentViewUtils::GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDoc, L"pUiDoc为空",L"GDMPLab",L"2024-03-30");
    pUiDoc->UpdateView();

    // 启动画直轮廓线的命令
    ICommandManager* pCommandManager = ICommandManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pCommandManager, L"pInstance为空",L"GDMPLab",L"2024-03-30");
    pCommandManager->SendCommand(ID_CMD_STRUCTURE_DRAW_ROOF_STRAIGHT_PROFILE);

    return nullptr;
}

UniIdentity CmdEditRoofProfile::GetCategory() const
{
    UniIdentity categoryUid = BuiltInCategoryUniIdentities::BICU_NEW_ROOF;
    return categoryUid;
}

void CmdEditRoofProfile::GetProfileCurvesAndSlopeLines(ElementId instanceId, std::vector<IElement*>& profileCurveElements,
    std::vector<IElement*>& slopeLineElements) const
{
    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IInstance* pInstance = quick_cast<IInstance>(pDoc->GetElement(instanceId));
    DBG_WARN_AND_RETURN_VOID_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    IStructureRoof* pRoof = IStructureRoof::Get(pInstance);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pRoof, L"pRoof为空",L"GDMPLab",L"2024-03-30");

    const std::vector<ElementId>& profileCurveIds = pRoof->GetProfileCurveIds();
    FOR_EACH(id, profileCurveIds)
    {
        IElement* pElement = pDoc->GetElement(id);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
        if (StructureRoofProfileUsedModelLineUtils::IsModelLineUsedForRoofProfile(pElement))
        {
            profileCurveElements.push_back(pElement);
        }
    }

    const std::vector<ElementId>& slopeLineIds = pRoof->GetSlopeLineIds();
    if (slopeLineIds.size() > 0)
    {
        FOR_EACH(id, slopeLineIds)
        {
            IElement* pElement = pDoc->GetElement(id);
            DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
            slopeLineElements.push_back(pElement);
        }
    }
}
